package revisaosistematica;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;



/**
 *
 * @author claudiane
 */
public class ModeloVetorial {

	//Calcula o logaritimo na base 2
	public static float log2(float num)
	{
		return (float)(Math.log(num)/Math.log(2));
	}


	//Calcula do idf
	public static float idf(float totalDocsToken, int totalDocs){
		return log2((float)totalDocs / totalDocsToken);

	}

	//Calcula o tf
	public static float tf(float valor){
		return (1 + log2(valor));
	}

	//Calcula o peso de cada token
	public static float pesoTfIdf(float tf, float idf){

		return tf*idf;
	}

	//Retorna uma lista ordenada de ranks
	public static void ordenaLista(List<Registro> listaRank) {

		Collections.sort(listaRank, new Comparator<Registro>() {

			@Override
			public int compare(Registro t1, Registro t2) { 

				return ((Float)t2.getValor()).compareTo((Float)t1.getValor());
			}
		}
				);

	}

	//Calcula o Rank da consulta
	public static List<Registro> calculoRank(String consulta, float vetorNorma[], float vetorNormaAbs[], HashMap<String, List<Registro>> hash){

		//foi criado a hash para obter eficiencia no calculo do rank
		//hash para armazenar o numero do doc e o rank para cada consulta
		//Map<Integer, Float> hashRank = new HashMap<Integer,Float>();
		Map<Integer, RegistroRank> hashRank = new HashMap<Integer,RegistroRank>();


		//apos ter a hash com o calculo do rank foi acidiona em uma lista ordenando os docs pelo rank
		List<Registro> listaRank = new ArrayList<Registro>();

		String[] expressoesConsulta = Extracao.extrairExpressoes(consulta);
		
		consulta = consulta.toLowerCase();
		consulta = Extracao.getPreProcessaDoc(consulta);
		String[] tokensConsulta = consulta.split(" ");

		HashSet<String> tokens = new HashSet<String>();
		for (String t : tokensConsulta) {
			t = t.trim();
			if (!t.isEmpty()) {
				tokens.add(t);
			}
		}
		tokens.addAll(Arrays.asList(expressoesConsulta));
		tokensConsulta = tokens.toArray(new String[]{});

		// Percorre os tokens da consulta
		for (String token: tokensConsulta){

			token = token.trim();

			//verifica se o token da consulta está na hash de tokens dos documentos
			if (hash.containsKey(token)){

				//Atribui na listaValor os valores de cada chave da hash
				List<Registro> listaValor = hash.get(token);

				//Percorre para cada registro da lista de valores do token analisado
				for (Registro registro: listaValor){

					String titulo = registro.getTitulo();

					//retorna o indice que é o numero do documento
					int indice = registro.getIndice();
					
					//obtendo o valor do peso do token para o titulo e abstract
					float pesoTitulo = registro.getValor();
					float pesoAbs = registro.getValorAbs();


					//Calcula o rank para o titulo e abs fazendo a frequencia normalizada
					float rankTitulo = pesoTitulo / vetorNorma[indice];
					float rankAbs = pesoAbs / vetorNormaAbs[indice];

					//calcula o rank final
					float rankFinal = (0.1f)*rankTitulo + (0.9f)*rankAbs;

					//verifica se a hash criada para o rank já tem o documento passado
					//caso tenha incrementa apenas o valor do rank
					//senao adiciona o documento e o valor do rank
					if ((hashRank.containsKey(indice))){
						float novo = hashRank.get(indice).getRank() + rankFinal;
						hashRank.put(indice, new RegistroRank(novo,titulo));
					}else{
						hashRank.put(indice, new RegistroRank(rankFinal,titulo));
					}
				}
			}
		}

		System.out.println("Numero de Documentos Recuperados: "+hashRank.size());

		//Após ter a hash de rank construída
		//o conteúdo (numero do doc e o rank) foi transferido para uma Lista
		//a qual é ordenada pelo rank

		//obtem o conjunto de chaves da hash
		Set<Integer> chaves = hashRank.keySet();
		for (Integer chave: chaves){

			//obtem os valores para cada token(chave)
			float rank = hashRank.get(chave).getRank();
			String titulo = hashRank.get(chave).getTitulo();

			listaRank.add(new Registro(chave,rank,0,titulo));
		}


		//Ordena a lista de acordo com o rank
		ordenaLista(listaRank);

		StringBuilder saidaArq = new StringBuilder();
		for (int i=0; i<listaRank.size(); i++){
			System.out.println("\tArtigo: "+listaRank.get(i).getIndice()+" "+"\tRank: "+listaRank.get(i).getValor()+"\tTitulo: "+listaRank.get(i).getTitulo());
			saidaArq.append((i+1)+";"+listaRank.get(i).getIndice()+" "+";"+listaRank.get(i).getValor()+";"+listaRank.get(i).getTitulo().trim()+"\n");
		}
		Util.escreverSaidaRanking(saidaArq.toString());

		//retorna a lista de rank ordenada
		return listaRank;
	}
}